<?php
/**
 * @file
 */
/**
 * Implements of hook_entity_info()
 */
function wordgame_entity_info() {
  $return = array(
    'wordgame' => array(
      'label' => t('Words Game'),
      'controller class' => 'WordGameController',
      'base table' => 'wordgame',
      'uri callback' => 'wordgame_uri',
      'fieldable' => TRUE,
      'entity keys' => array(
        'id' => 'wgid',
      ),
      'bundles' => array(
        'wordgame' => array(
          'label' => t('Words Game'),
        ),
      ),
      'view modes' => array(
        'full' => array(
          'label' => t('WordsGame'),
          'custom settings' => FALSE,
        ),
      ),
    ),
  );
  return $return;
}

/**
 * Implements callback_entity_info_uri().
 */
function wordgame_uri($wordgame) {
  return array(
    'path' => 'wordgame/' . $wordgame->wgid,
    'options' => array('fragment' => 'wordgame-' . $wordgame->wgid),
  );
}

/**
 * Load the entire wordgame by wgid.
 *
 * @param $wgid
 *   The identifying comment id.
 * @param $reset
 *   Whether to reset the internal static entity cache. Note that the static
 *   cache is disabled in comment_entity_info() by default.
 *
 * @return
 *   The comment object.
 */
function wordgame_load($wgid, $reset = FALSE) {
  $wordgame = wordgame_load_multiple(array($wgid), array(), $reset);
  return $wordgame ? $wordgame[$wgid] : FALSE;
}

/**
 * Load wordgames from the database.
 *
 * @param $wgids
 *   An array of wordgame IDs.
 * @param $conditions
 *   (deprecated) An associative array of conditions on the {wordgames}
 *   table, where the keys are the database fields and the values are the
 *   values those fields must have. Instead, it is preferable to use
 *   EntityFieldQuery to retrieve a list of entity IDs loadable by
 *   this function.
 * @param $reset
 *   Whether to reset the internal static entity cache. Note that the static
 *   cache is disabled in wordgame_entity_info() by default.
 *
 * @return
 *   An array of comment objects, indexed by wordgame ID.
 *
 * @see entity_load()
 * @see EntityFieldQuery
 *
 * @todo Remove $conditions in Drupal 8.
 */
function wordgame_load_multiple($wgids = array(), $conditions = array(), $reset = FALSE) {
  return entity_load('wordgame', $wgids, $conditions, $reset);
}

/**
 * Load the entire wordgame by sid.
 *
 * @param $sid
 *   The identifying game id.
 * @param $reset
 *   Whether to reset the internal static entity cache. Note that the static
 *   cache is disabled in comment_entity_info() by default.
 *
 * @return
 *   The game object.
 */
function wordgame_load_by_sid($sid, $reset = FALSE) {
  $wordgames = wordgame_load_multiple(array(), array('sid' => $sid, 'status' => 0), $reset);
  return $wordgames ? reset($wordgames): FALSE;
}

/**
 * Load the entire wordgame by uid.
 *
 * @param $sid
 *   The identifying game id.
 * @param $reset
 *   Whether to reset the internal static entity cache. Note that the static
 *   cache is disabled in comment_entity_info() by default.
 *
 * @return
 *   The game object.
 */
function wordgame_load_by_uid($uid, $reset = FALSE) {
  $wordgames = wordgame_load_multiple(array(), array('uid' => $uid, 'status' => 0), $reset);
  return $wordgames ? reset($wordgames): FALSE;
}

/**
 * Prepares a wordgame object for editing.
 *
 * Fills in a few default values, and then invokes hook_prepare() on the wordgame
 * type module, and hook_wordgame_prepare() on all modules.
 *
 * @param $wordgame
 *   A wordgame object.
 */
function wordgame_object_prepare($wordgame) {
  global $user;
  // Load default values
  $user_level = wordgame_user_level();
  $wordgame->columns = variable_get('wordgame_board_columns', 20);
  $wordgame->rows = variable_get('wordgame_board_rows', 20);
  $wordgame->max_guest = !empty($user_level->max_guest) ? $user_level->max_guest : variable_get('wordgame_max_guest', 2);
  $wordgame->max_summon = !empty($user_level->max_summon) ? $user_level->max_summon :variable_get('wordgame_max_summon', 2);
  $wordgame->max_word = !empty($user_level->max_word) ? $user_level->max_word :variable_get('wordgame_max_summon', 2);

  if (!isset($wordgame->wgid) || isset($wordgame->is_new)) {
    // add words
    $wordgame->board = array();
    $wordgame->words = array();
    $wordgame->amounts = array();
    $wordgame->results = array();
    $word = wordgame_first_word($wordgame);
    wordgame_summon_word($word, $wordgame);
    // Add user, datetime, session id
    $wordgame->uid = $user->uid;
    $wordgame->created = REQUEST_TIME;
    $wordgame->sid = session_id();
  }
  else {
    $wordgame->created = REQUEST_TIME;
  }

  // Prepare wordgame
  if (!isset($wordgame->uid)) {
    $wordgame->uid = $user->uid;
  }
  if (!isset($wordgame->created)) {
    $wordgame->created = REQUEST_TIME;
  }
  if (!isset($wordgame->status)) {
    $wordgame->status = 0;
  }
  if (!isset($wordgame->sid)) {
    $wordgame->sid = session_id();
  }

  module_invoke_all('wordgame_prepare', $wordgame);
}

/**
 * Save wordgame
 *
 * @param $wordgame
 */
function wordgame_save($wordgame) {
  $transaction = db_transaction();

  wordgame_object_prepare($wordgame);

  try {
    field_attach_presave('wordgame', $wordgame);

    // Determine if we will be inserting a new node.
    if (!isset($wordgame->is_new)) {
      $wordgame->is_new = empty($wordgame->wgid);
    }

    $wordgame->created = REQUEST_TIME;

    $fields = array('board', 'words', 'guests', 'results', 'amounts');
    // Serialized data
    foreach ($fields as $name) {
      if (is_array($wordgame->{$name})) {
        $wordgame->{$name} = serialize($wordgame->{$name});
      }
    }
    // Let modules modify the node before it is saved to the database.
    module_invoke_all('wordgame_presave', $wordgame);
    module_invoke_all('entity_presave', $wordgame, 'wordgame');

    // Save the node and node revision.
    if ($wordgame->is_new) {
      // For new wordgame_word, save new records for the wordgame_word itself
      drupal_write_record('wordgame', $wordgame);
      $op = 'insert';
    }
    else {
      // For existing wordgame_word, update the wordgame_word record which matches the value of
      // $wordgame_word->wid.
      drupal_write_record('wordgame', $wordgame, 'wgid');
      $op = 'update';
    }

    // Save fields.
    $function = "field_attach_$op";
    $function('wordgame', $wordgame);

    module_invoke_all('wordgame_' . $op, $wordgame);
    module_invoke_all('entity_' . $op, $wordgame, 'wordgame');

    // Clear internal properties.
    unset($wordgame->is_new);

    // Unserialized data
    foreach ($fields as $name) {
      if (!is_array($wordgame->{$name})) {
        $wordgame->{$name} = unserialize($wordgame->{$name});
      }
    }
    // Clear the static loading cache.
    entity_get_controller('wordgame')->resetCache(array($wordgame->wgid));
    // Ignore slave server temporarily to give time for the
    // saved wordgame to be propagated to the slave.
    db_ignore_slave();
  }
  catch (Exception $e) {
    $transaction->rollback();
    watchdog_exception('wordgame', $e);
    throw $e;
  }
}

/**
 * Generates an array for rendering the given wordgame.
 */
function wordgame_view($wordgame) {
  $build = array(
    '#theme' => 'wordgame',
    '#wordgame' => $wordgame,
    '#attached' => array(
      'js' => array(drupal_get_path('module', 'wordgame') . "/wordgame.js")
    )
  );
  drupal_add_library('system', 'ui.dialog');
  $build['board'] = wordgame_load_board($wordgame);
  $items = array();
  $amounts = !empty($wordgame->amounts) ? $wordgame->amounts : array();

  arsort($amounts);

  foreach ($amounts as $char => $amount) {
    if ($amount != 0) {
      $items[] = array(
        'data' => $char . '<span class="amounts">' . $amount . '</span>',
        'class' => array('letter', 'letter-' . $char)
      );
    }
  }  
  $build['letters'] = array(
    '#theme' => 'item_list',
    '#items' => $items
  );
  if ($wordgame) {
    // Js Settings to client
    $js_settings['wordgame']['games'][$wordgame->wgid] = array(
      'wgid' => $wordgame->wgid,
      'title' => t('Choose letter')
    );
    drupal_add_js($js_settings, 'setting');
    //Send a content channel token to Node.js.
    nodejs_send_content_channel_token('wordgame_' . $wordgame->wgid, TRUE);
  }

  return $build;
}

/**
 * Load board
 */
function wordgame_load_board($wordgame) {
  $board = $wordgame->board;
  $guests = $wordgame->guests;
  $words = $wordgame->words;
  $rows = array();
  for ($i = 1; $i <= $wordgame->rows; $i++) {
    for ($j = 1; $j <= $wordgame->columns; $j++) {
      $vars = array('type' => 'empty', 'row' => $i, 'col' => $j, 'letter' => '', 'word_index' => NULL);
      if (!empty($board[$i][$j])) {
        $vars['type'] = 'visible';
        $vars['letter'] = $board[$i][$j]['letter'];
        foreach ($board[$i][$j]['word'] as $word) {
          $index = array_search($word, array_keys($words));
          $vars['word_index'][] = "word-" . ($index + 1);
        }
      }
      if (!empty($guests[$i][$j])) {
        $vars['type'] = 'guest';
        $vars['letter'] = t('?');
      }
      $rows[$i][$j] = array('data' => theme('wordgame_letter', $vars));
    }
  }

  return array(
    '#theme' => 'table',
    '#header' => array(),
    '#rows' => $rows,
    '#wordgame' => $wordgame
  );
}

/**
 * Controller class for wordgame.
 *
 * This extends the DrupalDefaultEntityController class, adding required
 * special handling for comment objects.
 */
class WordGameController extends DrupalDefaultEntityController {
  protected function attachLoad(&$wordgames, $revision_id = FALSE) {
    // Call the default attachLoad() method. This will add fields and call
    $user_level = wordgame_user_level();
    foreach ($wordgames as $key => $wordgame) {
      $wordgames[$key]->board = unserialize($wordgames[$key]->board);
      $wordgames[$key]->words = unserialize($wordgames[$key]->words);
      $wordgames[$key]->guests = unserialize($wordgames[$key]->guests);
      $wordgames[$key]->results = unserialize($wordgames[$key]->results);
      $wordgames[$key]->amounts = unserialize($wordgames[$key]->amounts);
      $wordgame->max_guest = !empty($user_level->max_guest) ?
        $user_level->max_guest :
        variable_get('wordgame_max_guest', 2);
      $wordgame->max_summon = !empty($user_level->max_summon) ?
        $user_level->max_summon :
        variable_get('wordgame_max_summon', 2);
    }
    // hook_wordgame_load().
    parent::attachLoad($wordgames, $revision_id);
  }
}
